#include "qtcpdriver.h"

#include "qmission.h"
#include "qmissionmanager.h"

#include "../property/qabstractproperty.h"
#include "../qpropertyfactory.h"
#include "../qcommonstruct.h"
#include "../qdriverfactory.h"
#include "../qdatamanager.h"
#include "../qdata.h"

#include <QHostAddress>

QTCPDriverHost::QTCPDriverHost(QAbstractHost *parent):
    QAbstractDriver(parent),
    m_tcp_socket(NULL)
{
}

void QTCPDriverHost::create_object()
{
    m_object=new QObject(this);
    m_object->setObjectName("tcp");
}

void QTCPDriverHost::init_property()
{
    QAbstractDriver::init_property();

    QAbstractProperty *pro;

    pro=QPropertyFactory::create_property("IPAdress");
    if(pro!=NULL)
    {
        pro->set_property("name","ip_address");
        pro->set_attribute("show_name",tr("IP Address"));
        pro->set_attribute("group","Attributes");
        pro->set_attribute(ATTR_NEEDSAVE,true);
        pro->set_attribute("Report",true);
        m_object->setProperty("ip_address",0xc0a80101);
        insert_property(pro);
    }

    pro=QPropertyFactory::create_property("Number");
    if(pro!=NULL)
    {
        pro->set_property("name","ip_port");
        pro->set_attribute("show_name",tr("IP Port"));
        pro->set_attribute("group","Attributes");
        pro->set_attribute(ATTR_NEEDSAVE,true);
        pro->set_attribute("Report",true);
        m_object->setProperty("ip_port",100);
        insert_property(pro);
    }

    pro=QPropertyFactory::create_property("Number");
    if(pro!=NULL)
    {
        pro->set_property("name","max_read");
        pro->set_attribute("show_name",tr("Max Read"));
        pro->set_attribute("group","Attributes");
        pro->set_attribute(ATTR_NEEDSAVE,true);
        m_object->setProperty("max_read",16);
        insert_property(pro);
    }
}

QString QTCPDriverHost::get_show_name()
{
    return tr("TCP");
}

void QTCPDriverHost::start()
{

    QTimer::singleShot(100,this,SLOT(connect_slot()));
}

void QTCPDriverHost::connect_slot()
{
    closed();
    m_mission_manager->set_max_read(get_property_value("max_read").toInt());
    m_mission_manager->set_max_write(1);

    m_tcp_socket=new QTcpSocket(this);
    int port=get_property_value("ip_port").toInt();
    int ip=get_property_value("ip_address").toInt();
    m_tcp_socket->connectToHost(QHostAddress(ip),port);
    if(!m_tcp_socket->waitForConnected(3000))
    {
        error_exec("Connect failed!");
        closed();
    }
    else
    {
        connect(m_tcp_socket,SIGNAL(readyRead()),this,SLOT(readyread()));

        QString id;
        foreach(tagDriverDataInfo *data,m_datas)
        {
            id=m_mission_manager->add_mission(data);
            if(id!="" && data->m_type==DT_WRITE)
            {
                if(data->m_data_uuid!="")
                {
                    m_mission_manager->get_mission(id)->setProperty("send_data",data->m_data_uuid);
                }
                else
                {
                    m_mission_manager->get_mission(id)->setProperty("send_data",data->m_temp_data);
                }
            }
        }

        int addr,len;
        enDataTpye type;
        int machine_address;
        uchar ch[64];
        ushort crc;
        foreach(QMission* ms,m_mission_manager->get_missions())
        {
            addr=ms->get_address();
            len=ms->get_length();
            type=ms->get_mission_type();
            machine_address=ms->get_machine_address();
            if(type==DT_READ)
            {
                ch[0]=machine_address;
                ch[1]=0x03;
                ch[2]=(addr>>8)&0xff;
                ch[3]=addr&0xff;
                ch[4]=(len>>8)&0xff;
                ch[5]=len&0xff;
                crc=get_crc(ch,6);
                ch[6]=(crc>>8)&0xff;
                ch[7]=crc&0xff;
                ms->set_send_buffer(QByteArray((char*)ch,8));
                ms->setProperty("recv_len",5+2*len);
            }
            else if(type==DT_WRITE)
            {
                update_send_data(ms);
            }
        }

        m_timer->start(10);
    }
}

void QTCPDriverHost::closed()
{
    m_timer->stop();
    if(m_tcp_socket!=NULL)
    {
        delete m_tcp_socket;
        m_tcp_socket=NULL;
    }
}

void QTCPDriverHost::readyread()
{
    QByteArray data=m_tcp_socket->readAll();
    m_recv_data+=data;
    if(data.size()>0)
    {
        report_communicate(2,data);
    }

    QMission* ms=m_mission_manager->get_mission(m_current_mission_id);
    if(ms==NULL)
    {
        m_recv_data=QByteArray();
        return;
    }
    if(((m_recv_data[1]&0xff)>>7)==1)
    {
        if(m_recv_data.size()>=5)
        {
            ms->set_recv_buffer(m_recv_data.left(5));
            mission_done(ms);
            m_current_mission_id="";
        }
    }
    else
    {
        if(m_recv_data.size()>=ms->property("recv_len").toInt())
        {
            ms->set_recv_buffer(m_recv_data.left(ms->property("recv_len").toInt()));
            mission_done(ms);
            m_current_mission_id="";
        }
    }
}
void QTCPDriverHost::mission_done(QMission *ms)
{
    m_recv_data=QByteArray();
    QByteArray data=ms->get_recv_buffer();
    int size=data.size();
    ushort crc=get_crc((uchar*)data.data(),size-2);

    if(crc!=((data[size-2]&0xff)<<8)+(data[size-1]&0xff))
    {
        m_retry--;
        if(m_retry==0)
        {
            closed();
        }
        else
        {
            ms->set_mission_status(MS_RETRY);
        }
    }
    else
    {

        m_retry=get_property_value("retry_times").toInt();
        if(ms->get_period()<101)
        {
            ms->set_mission_status(MS_DELETE);
        }
        else
        {
            ms->set_mission_status(MS_READY);
            ms->set_last_time(QDateTime::currentDateTime());
        }

        if(data.size()==5)
        {
            error_exec(QString("Error:%1").arg(data[2]&0xff));
            return;
        }

        if(ms->get_mission_type()==DT_READ)
        {
            int s=ms->get_address();

            QMapIterator<QString,tagDriverDataInfo*> it(ms->get_address_info());
            double d;
            while(it.hasNext())
            {
                it.next();
                tagDriverDataInfo *info=it.value();
                int temp=((data[(info->m_data_address-s)*2+3]&0xff)<<8)+
                        (data[(info->m_data_address-s)*2+4]&0xff);
                d=temp*1.0/info->m_scale;
                if(it.value()->m_data_uuid!="")
                {
                    m_data_manager->set_value(info->m_data_uuid,d);
                }
                else
                {
                    info->m_temp_data=temp;
                }
            }
        }
    }
}


void QTCPDriverHost::update_send_data(QMission *ms)
{
    if(ms->get_mission_type()==DT_WRITE)
    {
        int addr=ms->get_address();
        uchar ch[64];
        ch[0]=ms->get_machine_address();;
        ch[1]=0x06;
        ch[2]=(addr>>8)&0xff;
        ch[3]=addr&0xff;
        QVariant v=ms->property("send_data");
        if(v.type()==QVariant::Int)
        {
            int temp=v.toInt();
            ch[4]=(temp>>8)&0xff;
            ch[5]=temp&0xff;
        }
        else
        {
            tagDataInfo *t=m_data_manager->get_data(v.toString());
            if(t!=NULL)
            {
                int temp=t->m_value.toInt();
                ch[4]=(temp>>8)&0xff;
                ch[5]=temp&0xff;
            }
            else
            {
                ch[4]=ch[5]=0;
            }
        }
        int crc=get_crc(ch,6);
        ch[6]=(crc>>8)&0xff;
        ch[7]=crc&0xff;
        ms->set_send_buffer(QByteArray((char*)ch,8));
        ms->setProperty("recv_len",8);
    }
}

void QTCPDriverHost::write(const QByteArray &data)
{
    m_recv_data=QByteArray();
    m_tcp_socket->write(data);
    report_communicate(1,data);
}


qRegisterDriver("base.tcp",QTCPDriverHost,1000)
